/**************************************************************************
Date: 2020-08-12
Description: xjson封装
**************************************************************************/

#ifndef __CXJSON__H__
#define __CXJSON__H__

#include "xpack/xpack.h"
#include "xpack/json.h"
#include "CNetworkServiceHeader.h"

#include <QDebug>
#include <QDir>
#include <cstdlib>
#include <io.h>
#include <tchar.h>
#include <fcntl.h>
#include <locale>
#include <codecvt>  // std::codecvt_utf8
using namespace std;
// 判断类或结构体是否有 CMD_DATAI 宏
template<typename T>
struct has_member_cmd_func
{
private:
    static string data;
private:
    template<typename U>
        static auto Check(int) -> decltype( std::declval<U>().toJsonString(data), std::declval<U>().loadJsonString(data),std::true_type() );
    template<typename U>
        static std::false_type Check(...);
public:
    enum { value = std::is_same<decltype(Check<T>(0)),std::true_type>::value  };
};


/* 模板函数，检查T是否有名为's'的成员
* value 为bool型检查结果
* type为s成员的类型(value为true是有效)
*/
#define HAS_MEMBER_XPACK(member)\
template<typename T>struct hasMember##member\
{\
    template <typename _T>static auto check(_T)->typename std::decay<decltype(_T::member)>::type;\
    static void check(...);\
    using type = decltype(check(std::declval<T>()));\
    enum { value = !std::is_void<type>::value };\
};

// 注册要检查的成员
// 使用时用hasMember+成员名<类名或者结构体名>::value
// 例如：
// HAS_MEMBER_XPACK(jxs)
// hasMemberjxs<JXS>::value
HAS_MEMBER_XPACK(__x_pack_value)

/*
  cmd 内容基类
*/
#define XJSON_FUNCI                                    	\
    string toJsonString() const {				  		\
        string ret ="";									\
        try{										  	\
            ret = xpack::json::encode(*this);		  	\
            return ret;							  		\
        }catch (...){									\
            qDebug("toJsonString error:%s",ret.c_str());	\
        }												\
        return ret;										\
    }													\
                                                        \
    string toJsonString(int flag, int indentCount, char indentChar) const {\
        string ret ="";									\
        try{										  	\
            ret = xpack::json::encode(*this,flag,indentCount,indentChar);\
            return ret;							  		\
        }catch (...){									\
            qDebug("toJsonString error:%s",ret.c_str());	\
        }												\
        return ret;										\
    }													\
                                                        \
                                                        \
    bool toJsonString(string &data) const {				\
        try{										  	\
            data = xpack::json::encode(*this);		  	\
            return true;							  	\
        }catch (...){									\
            qDebug("toJsonString error:%s",data.c_str());	\
        }												\
        return false;									\
    }													\
                                                        \
    bool toJsonString(string &data,int flag, int indentCount, char indentChar) const {\
        try{										  	\
            data = xpack::json::encode(*this,flag,indentCount,indentChar);\
            return true;							  	\
        }catch (...){									\
            qDebug("toJsonString error:%s",data.c_str());	\
        }												\
        return false;									\
    }													\
                                                        \
    bool loadJsonString(string &data) {					\
        try {											\
            xpack::json::decode(data, *this);			\
            return true;								\
        }catch (...){									\
            qDebug("loadJsonString error:%s",data.c_str());\
        }												\
        return false;									\
    }													\
    bool loadJsonString(const char *data) {				\
        try {											\
            xpack::json::decode(data, *this);			\
            return true;								\
        }catch (...){									\
            qDebug("loadJsonString error:%s",data);		\
        }												\
        return false;									\
    }													\
    bool loadFlie(string file_name) {\
        try {											\
            xpack::json::decode_file(file_name, *this);	\
            return true;								\
        }catch (runtime_error &err){					\
            qDebug("loadFlie error:%s",err.what());		\
        }catch (...){									\
            qDebug("loadFlie error:%s",file_name.c_str());\
        }				 								\
        return false;									\
    }													\
    bool toFlie(string file_name) {						\
        try {											\
            string pdstDir = file_name.substr(0,file_name.rfind("/"));\
            string mkdirCmd =pdstDir;				\
            std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;\
            std::wstring wideFilename = converter.from_bytes(pdstDir.c_str());\
            if (_taccess(wideFilename.c_str(), 0) != 0)\
            {											\
                QDir dir;                               \
                if(!dir.mkpath(QString::fromStdString(pdstDir))){		\
                    qDebug("error");\
                }										\
            }											\
            string data;								\
            this->toJsonString(data);					\
            ofstream  file1;							\
            std::wstring wstr = converter.from_bytes(file_name);\
            file1.open(wstr.c_str(),ios::out | ios::binary);\
            file1 << data.c_str();						\
            file1.close();								\
            return true;								\
        }catch (runtime_error &err){					\
            qDebug("toFlie error:%s",err.what());			\
        }catch (...){									\
            qDebug("toFlie error:%s",file_name.c_str());	\
        }												\
        return false;									\
    }


class NETWORKSERVICE_API XJson {
public:
    template <class T>
    static bool jsonDecode(const rapidjson::Value &data, T &val) {
        try {
            xpack::json::decode(data, val);
            return true;
        }catch (...){
            return false;
        }
    }

    template <class T>
    static bool jsonDecode(const std::string &data, T &val) {
        try {
            xpack::json::decode(data, val);
            return true;
        }catch (...){
            return false;
        }
    }

    template <class T>
        static bool jsonDecodeFile(const std::string &file_name, T &val) {
            try {
                xpack::json::decode_file(file_name, val);
                return true;
            }catch (...){
                return false;
            }
        }

    template <class T>
    static string jsonEncode(const T &val) {
        string ret="";
        try {
            ret= xpack::json::encode(val);
        }catch (...){
            qDebug("jsonEncode error \r\n");
        }
        return ret;
    }


    template <class T>
    static string jsonEncode(const T &val, int flag, int indentCount, char indentChar) {
        string ret="";
        try {
            ret =  xpack::json::encode(val,flag,indentCount,indentChar);
        }catch (...){
            qDebug("jsonEncode error \r\n");
        }
        return ret;
    }

};

#endif
